package com.boarsoft.boar.config.service;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import java.util.Properties;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.boarsoft.boar.BaseConfig;
import com.boarsoft.boar.file.FileExtService;
import com.boarsoft.common.util.FileUtil;
import org.codehaus.plexus.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import com.boarsoft.bean.ReplyInfo;
import com.boarsoft.boar.app.AppBiz;
import com.boarsoft.boar.app.AppHandler;
import com.boarsoft.boar.app.AppInstBiz;
import com.boarsoft.boar.entity.AppInfo;
import com.boarsoft.boar.entity.AppInst;
import com.boarsoft.boar.entity.FileInfo;
import com.boarsoft.boar.entity.FileVersion;
import com.boarsoft.boar.file.FileAppBiz;
import com.boarsoft.boar.file.FileBiz;
import com.boarsoft.boar.file.FileVersionBiz;
import com.boarsoft.boar.service.FileService;
import com.boarsoft.common.util.PropertiesUtil;

@Component("configFileSvc")
public class ConfigFileServiceImpl implements ConfigFileService {
	private static final Logger log = LoggerFactory.getLogger(ConfigFileServiceImpl.class);

	@Autowired
	private AppBiz appBiz;
	@Autowired
	private AppInstBiz appInstBiz;
	@Autowired
	private FileBiz fileBiz;
	@Autowired
	private FileAppBiz fileAppBiz;
	@Autowired
	private FileVersionBiz fileVersionBiz;
	@Autowired
	private ApplicationContext appCtx;
	@Autowired
	private FileService fileService;
	@Autowired
	protected FileExtService fileExtService;

	@Override
	public ReplyInfo<Object> replacePropVar(String by, String fileId, String env, String group,
			String key, String repl, String with) {
		log.info("{} is replacing prop key {} of file {} for {}/{}", by, key, fileId, env, group);
		FileInfo fi = fileBiz.get(fileId);
		String charset = fi.getCharset();
		// 修改配置文件
		try {
			byte[] ba = fileService.load(fileId, env, group);
			Properties prop = PropertiesUtil.fromBytes(ba, charset);
			String ov = prop.getProperty(key, "");
			String nv = StringUtils.replace(ov, repl, with);
			log.info("Replace properties key {} from {} to {}", key, ov, nv);
			prop.put(key, nv);
			// 生成新的文件版本
			ba = PropertiesUtil.getBytes(prop, charset);
			ReplyInfo<Object> ro = fileService.commit(by, fileId, env, group, ba);
			// 发布新版本
			if (ro.isSuccess()) {
				log.info("Replace properties key {} successfully", key);
				FileVersion fv = (FileVersion) ro.getData();
				// 更新相关分组的网关实例的配置，而不是inst2的配置
				return this.sync(fv.getId(), fv.getGroup());
			}
			return ReplyInfo.FAILED;
		} catch (Exception e) {
			log.error("{} replace prop key {} of file {} failed", by, key, fileId, e);
			return new ReplyInfo<Object>(e.getMessage());
		}
	}

	@Override
	public ReplyInfo<Object> sync(String id, String appId, String group) throws IllegalAccessException {
		FileVersion o = fileVersionBiz.get(id);
		String fileId = o.getFileId();
		byte[] bytes = null;
		try {
			bytes = fileService.load(o);
		} catch (IOException e) {
			log.error("Can not load config file with {},{},{}", //
					o.getPath(), fileId, id, e);
			return new ReplyInfo<Object>(e.getMessage());
		}
		FileInfo fi = fileBiz.get(fileId);
		// 遍历使用了此文件的应用
		AppInfo app = appBiz.get(appId);
		// 查找这些应用的实例
		AppHandler ah = appCtx.getBean(app.getHandler(), AppHandler.class);
		List<AppInst> aiLt = appInstBiz.list(o.getEnv(), app.getId(), group, null);
		for (AppInst ai : aiLt) {
			ah.sync(app, ai, fi.getCode(), bytes, fi.getDeployPath());
		}
		return ReplyInfo.SUCCESS;
	}

	@Override
	public ReplyInfo<Object> sync2(String id, String appId, String appInstId) throws IllegalAccessException {
		FileVersion o = fileVersionBiz.get(id);
		String fileId = o.getFileId();
		byte[] bytes = null;
		try {
			bytes = fileService.load(o);
		} catch (IOException e) {
			log.error("Can not load config file with {},{},{}", //
					o.getPath(), fileId, id, e);
			return new ReplyInfo<Object>(e.getMessage());
		}
		FileInfo fi = fileBiz.get(fileId);
		AppInfo app = appBiz.get(appId);
		AppInst ai = appInstBiz.get(appInstId);
		AppHandler ah = appCtx.getBean(app.getHandler(), AppHandler.class);
		ah.sync(app, ai, fi.getCode(), bytes, fi.getDeployPath());
		return ReplyInfo.SUCCESS;
	}

	@Override
	public ReplyInfo<Object> sync(String id, String group) throws IllegalAccessException {
		log.info("Sync file version {} to group {}", id, group);
		FileVersion o = fileVersionBiz.get(id);
		String fileId = o.getFileId();
		byte[] bytes = null;
		try {
			bytes = fileService.load(o);
		} catch (IOException e) {
			log.error("Can not load config file version {} from {}", id, o.getPath(), e);
			return new ReplyInfo<Object>(e.getMessage());
		}
		// 取文件监息
		FileInfo fi = fileBiz.get(fileId);
		// 遍历使用了此文件的应用
		List<AppInfo> appLt = fileAppBiz.list(fileId);
		for (AppInfo app : appLt) {
			log.info("Sync file version {} to app {}", id, app.getId());
			// 查找并遍历当前应用的实例，同步配置文件
			AppHandler ah = appCtx.getBean(app.getHandler(), AppHandler.class);
			List<AppInst> aiLt = appInstBiz.list(o.getEnv(), app.getId(), group, null);
			for (AppInst ai : aiLt) {
				log.info("Sync file version {} to app inst {}", id, ai.getId());
				ah.sync(app, ai, fi.getCode(), bytes, fi.getDeployPath());
			}
		}
		return ReplyInfo.SUCCESS;
	}

	@Override
	public void clone(String appId, String fromEnv, String toEnv) {
		List<FileVersion> fileVersions=fileVersionBiz.findByEnv(appId, fromEnv);
		for(FileVersion fromFile:fileVersions){
			FileVersion toFile=fileVersionBiz.copy(fromFile.getId(),toEnv);
			fileExtService.copyFile(fileService.getFilePath(fromFile),fileService.getFilePath(toFile));
		}
	}

	@Override
	public void exportConfig(String appId, String fromEnv, String exportRoot) throws FileNotFoundException {
		//1.导出file_version
		List<FileVersion> fileVersions=fileVersionBiz.findByEnv(appId, fromEnv);
		FileUtil.write(new File(exportRoot+"configfile/file_version.data"), JSON.toJSONString(fileVersions));
		//2.导出文件
		for(FileVersion fromFile:fileVersions){
			fileExtService.copyFile(fileService.getFilePath(fromFile),
					new StringBuilder(BaseConfig.PATH_PRIVATE)
							.append("/configfile/").toString());

		}
	}

	@Override
	public void importConfig(String importRoot) throws IOException {
		//1.导入file_version
		String context = FileUtil.read(new File(importRoot + "configfile/file_version.data"));
		List<FileVersion> lst= JSONObject.parseArray(context,FileVersion.class);
		for(FileVersion cv:lst){
			fileVersionBiz.add(cv);
			//2.导入文件
			fileExtService.copyFile(new StringBuilder(importRoot)
					.append("/configfile/").toString(),fileService.getFilePath(cv));
		}
	}
}